package Rangel.common.world.helper;

import Rangel.common.RangelConstants;
import Rangel.common.pathplanning.astar.graph.GraphModule;
import Rangel.common.world.entity.*;
import Rangel.common.world.tools.Util;
import Rangel.firebrigade.world.RangelFireBrigadeWorld;
import adf.agent.communication.MessageManager;
import adf.agent.communication.standard.bundle.MessageUtil;
import adf.agent.communication.standard.bundle.information.MessageBuilding;
import adf.agent.develop.DevelopData;
import adf.agent.info.AgentInfo;
import adf.agent.info.ScenarioInfo;
import adf.agent.info.WorldInfo;
import adf.agent.module.ModuleManager;
import adf.component.communication.CommunicationMessage;
import adf.component.module.AbstractModule;
import rescuecore2.messages.Command;
import rescuecore2.misc.Handy;
import rescuecore2.misc.Pair;
import rescuecore2.standard.entities.*;
import rescuecore2.standard.messages.AKSpeak;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.Property;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.*;

public class RangelWorldHelper extends AbstractModule {

    private int lastUpdateTime = -1; //最后更新时间

    protected Set<Road> roadsSeen; //看过的路
    protected Set<Building> buildingsSeen;  //看到的建筑物
    protected Set<Civilian> civiliansSeen;  //看到市民
    protected Set<FireBrigade> fireBrigadesSeen;//看到消防队
    protected Set<Blockade> blockadesSeen;//看到障碍物
    protected Set<StandardEntity> roads;//道路
    protected Collection<StandardEntity> civilians;//市民
    protected Set<StandardEntity> buildings;//建筑
    protected Set<StandardEntity> areas;//区域
    protected Set<StandardEntity> humans;//人
    protected Set<StandardEntity> agents;//智能体
    protected List<StandardEntity> fireBrigades;//消防队
    protected Set<StandardEntity> platoonAgents;//中心智能体
    protected Set<StandardEntity> hydrants;//消防栓
    protected Set<StandardEntity> gasStations;//加油站
    protected Set<StandardEntity> refuges;//避难所
    protected Set<RangelRoad> RangelRoads;//道路
    protected Map<EntityID, RangelRoad> RangelRoadIdMap;//道路的编号
    protected Map<EntityID, RangelBuilding> RangelBuildingIdMap;//建筑的编号
    protected GraphModule graph;//图形模块
    protected Paths paths;//路径
    protected List<IHelper> helpers = new ArrayList<>();
    protected Map<EntityID, EntityID> entranceRoads;//道路入口

    public float rayRate = 0.0025f;//辐射率
    protected Set<RangelBuilding> RangelBuildings;//建筑
    protected Map<EntityID, RangelBuilding> tempBuildingsMap;//临时建筑物编号
    protected Map<String, Building> buildingXYMap;//建立XY地图
    protected Map<String, Road> roadXYMap;//道路XY地图

    protected Set<EntityID> unvisitedBuildings = new HashSet<>();//没有搜寻的建筑
    protected Set<EntityID> visitedBuildings = new HashSet<>();//搜寻的建筑
    protected int worldTotalArea;//世界总面积
    protected List<RangelBuilding> shouldCheckInsideBuildings = new ArrayList<>();//应该检查建筑物内部的建筑列表
    protected Human selfHuman;//自己
    protected Building selfBuilding;
    protected PropertyHelper propertyHelper;
    protected int lastAfterShockTime = 0;//
    protected int aftershockCount = 0;
    protected Set<EntityID> burningBuildings;//燃烧的建筑物
    protected Set<EntityID> emptyBuildings;//空的建筑物
    protected Set<EntityID> thisCycleEmptyBuildings;//这个周期空的建筑物

    protected boolean CommunicationLess = false;//是否沟通少
    protected boolean isCommunicationLow = false;//是否沟通不足
    protected boolean isCommunicationMedium = false;//是否沟通媒介
    protected boolean isCommunicationHigh = false;//是否沟通高
    public boolean isWaterRefillRateInHydrantSet;
    public boolean isWaterRefillRateInRefugeSet;

    protected Set<RangelBuilding> estimatedBurningBuildings = new HashSet<>();//估计在燃烧的建筑物
    protected Long uniqueMapNumber;//唯一的地图编号
    protected Set<EntityID> borderBuildings;//边境的建筑物
    protected ScenarioInfo scenarioInfo;
    protected AgentInfo agentInfo;
    protected WorldInfo worldInfo;
    protected ModuleManager moduleManager;
    public BorderEntities borderFinder;//边界查找器
    protected int minX, minY, maxX, maxY;
    protected boolean isMapHuge = false;//地图巨大
    protected boolean isMapMedium = false;//地图中等
    protected boolean isMapSmall = false;//地图小
    private Set<EntityID> possibleBurningBuildings;//可能的燃烧建筑物
    private Set<EntityID> allCivilians;//所有市民

    private Set<EntityID> heardCivilians;//听到的市民
    private EntityID exploreTarget;//探索目标

    public RangelWorldHelper(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) {
        super(ai, wi, si, moduleManager, developData);
        this.worldInfo = wi;
        this.agentInfo = ai;
        this.scenarioInfo = si;
        this.moduleManager = moduleManager;
        this.developData = developData;
        this.roadsSeen = new HashSet<>();
        buildingsSeen = new HashSet<>();
        civiliansSeen = new HashSet<>();
        blockadesSeen = new HashSet<>();
        fireBrigadesSeen = new HashSet<>();
        RangelRoads = new HashSet<>();
        burningBuildings = new HashSet<>();
        emptyBuildings = new HashSet<>();
        thisCycleEmptyBuildings = new HashSet<>();
        civilians = new HashSet<>();
        allCivilians = new HashSet<>();

        buildings = new HashSet<>(getBuildingsWithURN());
        roads = new HashSet<>(getRoadsWithURN());
        areas = new HashSet<>(getAreasWithURN());
        humans = new HashSet<>(getHumansWithURN());
        agents = new HashSet<>(getAgentsWithURN());
        fireBrigades = new ArrayList<>(getFireBrigades());
        platoonAgents = new HashSet<>(getPlatoonAgentsWithURN());
        hydrants = new HashSet<>(getHydrantsWithURN());
        gasStations = new HashSet<>(getGasStationsWithUrn());
        refuges = new HashSet<>(getRefugesWithUrn());
        graph = new GraphModule(ai, wi, si, moduleManager, developData);
        RangelRoadIdMap = new HashMap<>();
        RangelBuildingIdMap = new HashMap<>();
        entranceRoads = new HashMap<>();
        buildingXYMap = new HashMap<>();
        roadXYMap = new HashMap<>();
        possibleBurningBuildings = new HashSet<>();
        heardCivilians = new HashSet<>();

        createUniqueMapNumber();//为建筑物创建唯一的地图编号
        setWorldCommunicationCondition();//设置世界通讯条件

        helpers.add(new PropertyHelper(this));
        helpers.add(new BuildingHelper(this, scenarioInfo, agentInfo, worldInfo));
        helpers.add(new RoadHelper(this, ai, wi, si, moduleManager, developData));
        helpers.add(new CivilianHelper(this, si, ai, wi));
        helpers.add(new VisibilityHelper(this, si, ai, wi));

        if (worldInfo.getEntity(agentInfo.getID()) instanceof Building) {
            selfBuilding = (Building) worldInfo.getEntity(agentInfo.getID());
        } else {
            selfHuman = (Human) worldInfo.getEntity(agentInfo.getID());
        }

        propertyHelper = this.getHelper(PropertyHelper.class);

        calculateMapDimensions();//计算地图尺寸

        StandardEntity entity = worldInfo.getEntity(agentInfo.getID());
        if (entity instanceof FireBrigade || entity instanceof PoliceForce || entity instanceof AmbulanceTeam) {//对为智能体的人建立建筑信息
            createRangelBuildings();
        }

        paths = new Paths(this, worldInfo, agentInfo, scenarioInfo);

        createRangelRoads();

        verifyMap();//在60个周期内不能跑完对角线的距离，地图大；30-60周期跑完地图中；30以内地图小

        borderBuildings = new HashSet<>();
        borderFinder = new BorderEntities(this);
        helpers.forEach(IHelper::init);

    }

    private void verifyMap() {//验证地图

        double mapDimension = Math.hypot(getMapWidth(), getMapHeight());

        double rate = mapDimension / RangelConstants.MEAN_VELOCITY_OF_MOVING;//移动的平均速度

        if (rate > 60) {
            isMapHuge = true;
        } else if (rate > 30) {
            isMapMedium = true;
        } else {
            isMapSmall = true;
        }


    }

    private void calculateMapDimensions() {//计算地图尺寸
        this.minX = Integer.MAX_VALUE;
        this.maxX = Integer.MIN_VALUE;
        this.minY = Integer.MAX_VALUE;
        this.maxY = Integer.MIN_VALUE;
        Pair<Integer, Integer> pos;
        for (StandardEntity standardEntity : worldInfo.getAllEntities()) {
            pos = worldInfo.getLocation(standardEntity);
            if (pos.first() < this.minX)
                this.minX = pos.first();
            if (pos.second() < this.minY)
                this.minY = pos.second();
            if (pos.first() > this.maxX)
                this.maxX = pos.first();
            if (pos.second() > this.maxY)
                this.maxY = pos.second();
        }
    }

    private void createUniqueMapNumber() {
        long sum = 0;
        for (StandardEntity building : getBuildings()) {
            Building b = (Building) building;
            int[] ap = b.getApexList();
            for (int anAp : ap) {
                if (Long.MAX_VALUE - sum <= anAp) {
                    sum = 0;
                }
                sum += anAp;
            }
        }
        uniqueMapNumber = sum;
    }

    public synchronized static RangelWorldHelper load(AgentInfo agentInfo, WorldInfo worldInfo, ScenarioInfo scenarioInfo, ModuleManager moduleManager, DevelopData developData) {
        RangelWorldHelper worldHelper = null;
        try {
            if (worldInfo.getEntity(agentInfo.getID()) instanceof FireBrigade) {
                worldHelper = moduleManager.getModule("World.FireBrigadeWorldHelper", "Rangel.firebrigade.world.RangelFireBrigadeWorld");
            } else {
                worldHelper = moduleManager.getModule("World.WorldHelper", "Rangel.common.world.helper.RangelWorldHelper");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (worldHelper == null) {
            if (worldInfo.getEntity(agentInfo.getID()) instanceof FireBrigade){//
                worldHelper = new RangelFireBrigadeWorld(agentInfo, worldInfo, scenarioInfo, moduleManager, developData);
            } else {
                worldHelper = new RangelWorldHelper(agentInfo, worldInfo, scenarioInfo, moduleManager, developData);
            }
        }
        return worldHelper;
    }

    protected Area centerOfMap;
    protected double pole = 0;

    public Area getCenterOfMap() {//获取地图中心
        if (centerOfMap != null) {
            return centerOfMap;
        }

        double ret;
        int min_x = Integer.MAX_VALUE;
        int max_x = Integer.MIN_VALUE;
        int min_y = Integer.MAX_VALUE;
        int max_y = Integer.MIN_VALUE;

        Collection<StandardEntity> areas = getAreas();

        long x = 0, y = 0;
        Area result;

        for (StandardEntity entity : areas) {
            Area area1 = (Area) entity;
            x += area1.getX();
            y += area1.getY();
        }

        x /= areas.size();
        y /= areas.size();
        result = (Area) areas.iterator().next();
        for (StandardEntity entity : areas) {
            Area temp = (Area) entity;
            if (Util.distance((int) x, (int) y, result.getX(), result.getY()) > Util.distance((int) x, (int) y, temp.getX(), temp.getY())) {
                result = temp;
            }

            if (temp.getX() < min_x) {
                min_x = temp.getX();
            } else if (temp.getX() > max_x)
                max_x = temp.getX();

            if (temp.getY() < min_y) {
                min_y = temp.getY();
            } else if (temp.getY() > max_y)
                max_y = temp.getY();
        }
        ret = (Math.pow((min_x - max_x), 2) +
                Math.pow((min_y - max_y), 2));
        ret = Math.sqrt(ret);
        pole = ret;
        centerOfMap = result;

        return result;
    }

    public ModuleManager getModuleManager() {
        return moduleManager;
    }

    public Paths getPaths() {
        return paths;
    }

    @Override
    public RangelWorldHelper updateInfo(MessageManager messageManager) {//更新信息
        super.updateInfo(messageManager);
        if (this.getCountUpdateInfo() >= 2) {
            return this;
        }
        if (lastUpdateTime == agentInfo.getTime()) {
            return this;
        }
        lastUpdateTime = agentInfo.getTime();

        reflectMessage(messageManager);

        roadsSeen.clear();//看过的路
        buildingsSeen.clear();//看到的建筑物
        blockadesSeen.clear();
        civiliansSeen.clear();//看到平民
        fireBrigadesSeen.clear();//看到消防队
        civilians = worldInfo.getEntitiesOfType(StandardEntityURN.CIVILIAN);
        civilians.forEach(civEntity -> allCivilians.add(civEntity.getID()));
        Collection<Command> heard = agentInfo.getHeard();
        heardCivilians.clear();
        if (heard != null) {
            heard.forEach(next -> {
                if (next instanceof AKSpeak && ((AKSpeak) next).getChannel() == 0 && !next.getAgentID().equals(agentInfo.getID())) {
                    AKSpeak speak = (AKSpeak) next;
                    Collection<EntityID> platoonIDs = Handy.objectsToIDs(getAgents());
                    if (!platoonIDs.contains(speak.getAgentID())) {//Civilian message
                        processCivilianCommand(speak);//处理平民命令
                        allCivilians.add(speak.getAgentID());
                    }
                }
            });
        }

        worldInfo.getChanged().getChangedEntities().forEach(changedId -> {
            StandardEntity entity = worldInfo.getEntity(changedId);
            if (entity instanceof Civilian) {
                Civilian civilian = (Civilian) entity;
                civiliansSeen.add(civilian);
            } else if (entity instanceof Building) {
                Building building = (Building) entity;
                Property brokennessProperty = building.getProperty(StandardPropertyURN.BROKENNESS.toString());//建筑破碎
                if (brokennessProperty.isDefined()) {
                    int newBrokennessValue = -1;
                    for (Property p : worldInfo.getChanged().getChangedProperties(building.getID())) {//获取更改的属性
                        if (p.getURN().endsWith(brokennessProperty.getURN())) {//如果以破碎的URN结尾
                            newBrokennessValue = (Integer) p.getValue();
                        }
                    }
                    if (building.getBrokenness() < newBrokennessValue) {
                        if (propertyHelper.getPropertyTime(brokennessProperty) > getLastAfterShockTime()) {
                            setAftershockProperties(agentInfo.getTime());
                        }
                    }
                }
                for (Property p : worldInfo.getChanged().getChangedProperties(building.getID())) {
                    building.getProperty(p.getURN()).takeValue(p);
                    propertyHelper.setPropertyTime(building.getProperty(p.getURN()), agentInfo.getTime());
                }

                RangelBuilding RangelBuilding = getRangelBuilding(building.getID());
                if (agentInfo.me() instanceof FireBrigade) {
                    if (building.isFierynessDefined() && building.isTemperatureDefined()) {
                        RangelBuilding.setEnergy(building.getTemperature() * RangelBuilding.getCapacity());
                        RangelBuilding.updateValues(building);
                    }
                }
                propertyHelper.addEntityProperty(building, agentInfo.getTime());
                if (building.getFieryness() > 0 && building.getFieryness() < 4) {
                    burningBuildings.add(building.getID());
                } else {
                    burningBuildings.remove(building.getID());
                }

                buildingsSeen.add(building);
                RangelBuilding.setSensed(agentInfo.getTime());
                if (building.isOnFire()) {
                    RangelBuilding.setIgnitionTime(agentInfo.getTime());
                }

            } else if (entity instanceof Road) {
                Road road = (Road) entity;
                roadsSeen.add(road);

                RangelRoad RangelRoad = getRangelRoad(entity.getID());
                if (RangelRoad.isNeedUpdate()) {
                    RangelRoad.update();
                }
                RangelRoad.setLastSeenTime(agentInfo.getTime());
                RangelRoad.setSeen(true);
            } else if (entity instanceof Blockade) {
                blockadesSeen.add((Blockade) entity);
            } else if (entity instanceof FireBrigade) {
                fireBrigadesSeen.add((FireBrigade) entity);
            }
        });

        helpers.forEach(IHelper::update);
        return this;
    }

    public void processCivilianCommand(AKSpeak speak) {//处理平民命令
        Civilian civilian = (Civilian) getEntity(speak.getAgentID());
        if (civilian == null) {
            civilian = new Civilian(speak.getAgentID());
            addNewCivilian(civilian);
        }
        if (!civilian.isPositionDefined()) {//是位置定义
            addHeardCivilian(civilian.getID());
        }
    }

    public void addNewCivilian(Civilian civilian) {
        getHelper(PropertyHelper.class).addEntityProperty(civilian, getTime());
        getHelper(CivilianHelper.class).setInfoMap(civilian.getID());
    }


    private void reflectMessage(MessageManager messageManager) {
        Set<EntityID> changedEntities = this.worldInfo.getChanged().getChangedEntities();
        changedEntities.add(this.agentInfo.getID());
        int time = this.agentInfo.getTime();
        int receivedTime;
        for (CommunicationMessage message : messageManager.getReceivedMessageList(MessageBuilding.class)) {
            MessageBuilding mb = (MessageBuilding) message;
            if (!changedEntities.contains(mb.getBuildingID())) {
                MessageUtil.reflectMessage(this.worldInfo, mb);
                if (mb.isRadio()) {
                    receivedTime = time - 1;
                } else {
                    receivedTime = time - 5;
                }
                if (agentInfo.me() instanceof FireBrigade) {
                    processBurningBuilding(mb, receivedTime);
                }
            }
        }
    }


    private void processBurningBuilding(MessageBuilding burningBuildingMessage, int receivedTime) {
        Building building;

        building = (Building) this.getEntity(burningBuildingMessage.getBuildingID());
        if (propertyHelper.getPropertyTime(building.getFierynessProperty()) < receivedTime) {
            building.setFieryness(burningBuildingMessage.getFieryness());
            propertyHelper.setPropertyTime(building.getFierynessProperty(), receivedTime);
            building.setTemperature(burningBuildingMessage.getTemperature());
            propertyHelper.setPropertyTime(building.getTemperatureProperty(), receivedTime);
            RangelBuilding RangelBuilding = this.getRangelBuilding(building.getID());
            switch (building.getFieryness()) {
                case 0:
                    RangelBuilding.setFuel(RangelBuilding.getInitialFuel());
                    break;
                case 1:
                    if (RangelBuilding.getFuel() < RangelBuilding.getInitialFuel() * 0.66) {
                        RangelBuilding.setFuel((float) (RangelBuilding.getInitialFuel() * 0.75));
                    } else if (RangelBuilding.getFuel() == RangelBuilding.getInitialFuel()) {
                        RangelBuilding.setFuel((float) (RangelBuilding.getInitialFuel() * 0.90));
                    }
                    break;

                case 2:
                    if (RangelBuilding.getFuel() < RangelBuilding.getInitialFuel() * 0.33
                            || RangelBuilding.getFuel() > RangelBuilding.getInitialFuel() * 0.66) {
                        RangelBuilding.setFuel((float) (RangelBuilding.getInitialFuel() * 0.50));
                    }
                    break;

                case 3:
                    if (RangelBuilding.getFuel() < RangelBuilding.getInitialFuel() * 0.01
                            || RangelBuilding.getFuel() > RangelBuilding.getInitialFuel() * 0.33) {
                        RangelBuilding.setFuel((float) (RangelBuilding.getInitialFuel() * 0.15));
                    }
                    break;
                case 4:
                case 5:
                case 6:
                case 7:
                    RangelBuilding.setWasEverWatered(true);
                    RangelBuilding.setEnergy(0);
                    break;

                case 8:
                    RangelBuilding.setFuel(0);
                    break;
            }
            RangelBuilding.setEnergy(building.getTemperature() * RangelBuilding.getCapacity());
            if (building.getFieryness() > 0 && building.getFieryness() < 4) {
                this.getBurningBuildings().add(building.getID());
                RangelBuilding.setIgnitionTime(this.getTime());
            } else {
                this.getBurningBuildings().remove(building.getID());
            }
        }
    }

    @Override
    public AbstractModule calc() {
        return this;
    }

    public <T extends IHelper> T getHelper(Class<T> c) {
        for (IHelper helper : helpers) {
            if (c.isInstance(helper)) {
                return c.cast(helper);
            }
        }
        throw new RuntimeException("Helper not available for:" + c);
    }

    public Set<RangelRoad> getRangelRoads() {
        return RangelRoads;
    }

    public RangelRoad getRangelRoad(EntityID id) {
        return RangelRoadIdMap.get(id);
    }

    public RangelBuilding getRangelBuilding(EntityID id) {
        return RangelBuildingIdMap.get(id);
    }

    public Set<RangelBuilding> getRangelBuildings() {
        return RangelBuildings;
    }

    public Set<Civilian> getCiviliansSeen() {
        return civiliansSeen;
    }

    private Collection<StandardEntity> getBuildingsWithURN() {//得到建筑物信息
        return worldInfo.getEntitiesOfType(
                StandardEntityURN.BUILDING,
                StandardEntityURN.REFUGE,
                StandardEntityURN.AMBULANCE_CENTRE,
                StandardEntityURN.POLICE_OFFICE,
                StandardEntityURN.FIRE_STATION,
                StandardEntityURN.GAS_STATION);
    }

    private Collection<StandardEntity> getHydrantsWithURN() {//得到消防栓
        return worldInfo.getEntitiesOfType(StandardEntityURN.HYDRANT);
    }

    private Collection<StandardEntity> getGasStationsWithUrn() {//得到汽油站
        return worldInfo.getEntitiesOfType(StandardEntityURN.GAS_STATION);
    }

    private Collection<StandardEntity> getRefugesWithUrn() {//得到避难所
        return worldInfo.getEntitiesOfType(StandardEntityURN.REFUGE);
    }

    private Collection<StandardEntity> getAreasWithURN() {//获取区域
        return worldInfo.getEntitiesOfType(
                StandardEntityURN.BUILDING,
                StandardEntityURN.REFUGE,
                StandardEntityURN.ROAD,
                StandardEntityURN.AMBULANCE_CENTRE,
                StandardEntityURN.POLICE_OFFICE,
                StandardEntityURN.FIRE_STATION,
                StandardEntityURN.HYDRANT,
                StandardEntityURN.GAS_STATION);
    }

    private Collection<StandardEntity> getHumansWithURN() {//得到人
        return worldInfo.getEntitiesOfType(
                StandardEntityURN.CIVILIAN,
                StandardEntityURN.FIRE_BRIGADE,
                StandardEntityURN.POLICE_FORCE,
                StandardEntityURN.AMBULANCE_TEAM);
    }

    private Collection<StandardEntity> getAgentsWithURN() {//得到代理人（三种智能体和三种中心智能体）
        return worldInfo.getEntitiesOfType(
                StandardEntityURN.FIRE_BRIGADE,
                StandardEntityURN.POLICE_FORCE,
                StandardEntityURN.AMBULANCE_TEAM,
                StandardEntityURN.FIRE_STATION,
                StandardEntityURN.POLICE_OFFICE,
                StandardEntityURN.AMBULANCE_CENTRE);
    }

    private Collection<StandardEntity> getPlatoonAgentsWithURN() {//得到中心智能体
        return worldInfo.getEntitiesOfType(
                StandardEntityURN.FIRE_BRIGADE,
                StandardEntityURN.POLICE_FORCE,
                StandardEntityURN.AMBULANCE_TEAM);
    }

    private Collection<StandardEntity> getRoadsWithURN() {//得到道路
        return worldInfo.getEntitiesOfType(StandardEntityURN.ROAD, StandardEntityURN.HYDRANT);
    }

    public Set<StandardEntity> getRefuges() {
        return refuges;
    }//得到街道

    private void createRangelRoads() {
        RangelRoads = new HashSet<>();
        RangelRoadIdMap = new HashMap<>();
        for (StandardEntity rEntity : getRoads()) {
            Road road = (Road) rEntity;
            RangelRoad RangelRoad = new RangelRoad(agentInfo, worldInfo, scenarioInfo, moduleManager, road, this);
            RangelRoads.add(RangelRoad);
            RangelRoadIdMap.put(road.getID(), RangelRoad);
            String xy = road.getX() + "," + road.getY();
            roadXYMap.put(xy, road);
        }
    }

    private void createRangelBuildings() {

        tempBuildingsMap = new HashMap<>(buildings.size());//临时建筑物地图
        RangelBuildings = new HashSet<>();

        getBuildings().forEach(standardEntity -> {
            Building building = (Building) standardEntity;
            String xy = building.getX() + "," + building.getY();
            buildingXYMap.put(xy, building);

            RangelBuilding RangelBuilding = new RangelBuilding(standardEntity, this, worldInfo, agentInfo);

            if ((standardEntity instanceof Refuge)
                    || (standardEntity instanceof FireStation)
                    || (standardEntity instanceof PoliceOffice)
                    || (standardEntity instanceof AmbulanceCentre)) {
                RangelBuilding.setFlammable(false);//设置为不燃
            }
            RangelBuildings.add(RangelBuilding);
            tempBuildingsMap.put(standardEntity.getID(), RangelBuilding);
            RangelBuildingIdMap.put(building.getID(), RangelBuilding);
            unvisitedBuildings.add(standardEntity.getID());
            worldTotalArea += RangelBuilding.getSelfBuilding().getTotalArea();
        });
        shouldCheckInsideBuildings.clear();

        if (getSelfHuman() instanceof FireBrigade) {
            RangelBuildings.parallelStream().forEach(b -> {
                Collection<StandardEntity> neighbour = worldInfo.getObjectsInRange(b.getSelfBuilding(), Wall.MAX_SAMPLE_DISTANCE);//获取范围内的对象
                for (StandardEntity entity : neighbour) {
                    if (entity instanceof Building) {
                        b.addRangelBuildingNeighbour(tempBuildingsMap.get(entity.getID()));
                    }
                }
            });
        }


        for (RangelBuilding b : RangelBuildings) {
            if (b.getEntrances() != null) {//获取入口
                Building building = b.getSelfBuilding();
                List<Road> rEntrances = BuildingHelper.getEntranceRoads(this, building);
                for (Road road : rEntrances) {
                    entranceRoads.put(road.getID(), b.getID());
                }
            }
        }
    }

    public Human getSelfHuman() {
        return selfHuman;
    }

    public Building getSelfBuilding() {
        return selfBuilding;
    }

    public StandardEntity getSelfPosition() {
        if (worldInfo.getEntity(agentInfo.getID()) instanceof Building) {
            return selfBuilding;
        } else {
            return agentInfo.getPositionArea();
        }
    }

    public Set<Road> getRoadsSeen() {
        return roadsSeen;
    }

    public Set<Building> getBuildingsSeen() {
        return buildingsSeen;
    }

    public Set<Blockade> getBlockadesSeen() {
        return blockadesSeen;
    }

    public Set<FireBrigade> getFireBrigadesSeen() {
        return fireBrigadesSeen;
    }

    public Set<StandardEntity> getRoads() {
        return roads;
    }

    public Set<StandardEntity> getBuildings() {
        return buildings;
    }

    public Set<StandardEntity> getAreas() {
        return areas;
    }

    public Set<StandardEntity> getAgents() {
        return agents;
    }

    public Set<StandardEntity> getHydrants() {
        return hydrants;
    }

    public Set<StandardEntity> getGasStations() {
        return gasStations;
    }

    public GraphModule getGraph() {
        return graph;
    }

    public void printData(String s) {
        System.out.println("Time:" + agentInfo.getTime() + " Me:" + agentInfo.me() + " \t- " + s);
    }

    public void putEntrance(EntityID buildingId, Entrance entrance) {
        entranceRoads.put(entrance.getID(), buildingId);
    }

    public <T extends StandardEntity> T getEntity(EntityID id, Class<T> c) {//获取实体
        StandardEntity entity;

        entity = worldInfo.getEntity(id);
        if (c.isInstance(entity)) {
            T castedEntity;

            castedEntity = c.cast(entity);
            return castedEntity;
        } else {
            return null;
        }
    }

    public StandardEntity getEntity(EntityID id) {
        return worldInfo.getEntity(id);
    }


    public int getLastAfterShockTime() {
        return lastAfterShockTime;
    }

    public int getAftershockCount() {
        return aftershockCount;
    }

    public void setAftershockProperties(int aftershockCount) {
        if (this.aftershockCount < aftershockCount) {
            this.aftershockCount = aftershockCount;
            if (selfHuman != null) {
                postAftershockAction();
            }
        }
    }

    public void postAftershockAction() {
        this.printData("New aftershock occurred! Time: " + agentInfo.getTime() + " Total: " + this.getAftershockCount());

        for (RangelRoad RangelRoad : this.getRangelRoads()) {
            RangelRoad.getParent().undefineBlockades();
        }
    }

    public Set<EntityID> getVisitedBuildings() {
        return visitedBuildings;
    }

    public Set<EntityID> getBurningBuildings() {
        return burningBuildings;
    }

    public void setBuildingVisited(EntityID buildingID, boolean sendMessage) {//设置建筑物被访问
        RangelBuilding RangelBuilding = getRangelBuilding(buildingID);
        if (selfHuman == null) {
            return;
        }
        if (!RangelBuilding.isVisited()) {
            RangelBuilding.setVisited();
            visitedBuildings.add(buildingID);
            unvisitedBuildings.remove(buildingID);
        }
        updateEmptyBuildingState(RangelBuilding, sendMessage);
    }

    public void updateEmptyBuildingState(RangelBuilding RangelBuilding, boolean sendMessage) {//更新空建筑状态
        if (!RangelBuilding.isVisited()) {
            return;
        }

        if (!emptyBuildings.contains(RangelBuilding.getID()) && RangelBuilding.getCivilians().isEmpty()) {
            if (sendMessage) {
                thisCycleEmptyBuildings.add(RangelBuilding.getID());
            }
            emptyBuildings.add(RangelBuilding.getID());
        }

        if (emptyBuildings.contains(RangelBuilding.getID()) && !RangelBuilding.getCivilians().isEmpty()) {
            emptyBuildings.remove(RangelBuilding.getID());
        }
    }

    public Rectangle2D getBounds() {
        return worldInfo.getBounds();
    }

    protected void setWorldCommunicationCondition() {//设置世界通讯条件


        if (scenarioInfo.getCommsChannelsCount() == 1) {//获取Comms频道数
            this.setCommunicationLess(true);
            return;
        }
        int size = 0;
        int maxSize = 0;
        String channelBandwidthKey = "comms.channels.NO.bandwidth";
        for (int i = 1; i < scenarioInfo.getCommsChannelsMaxPlatoon(); i++) {//获取Comms频道Max Platoon
            size = scenarioInfo.getRawConfig().getIntValue(channelBandwidthKey.replace("NO", String.valueOf(i)));
            maxSize = Math.max(maxSize, size);
        }

        if (size <= 256) {
            this.setCommunicationLow(true);
        } else if (size <= 1024) {
            this.setCommunicationMedium(true);
        } else {
            this.setCommunicationHigh(true);
        }
    }

    public void setCommunicationLess(boolean CL) {
        this.CommunicationLess = CL;
    }

    public boolean isCommunicationLess() {
        return CommunicationLess;
    }

    public void setCommunicationLow(boolean communicationLow) {
        isCommunicationLow = communicationLow;
    }

    public void setCommunicationMedium(boolean communicationMedium) {
        isCommunicationMedium = communicationMedium;
    }

    public void setCommunicationHigh(boolean communicationHigh) {
        isCommunicationHigh = communicationHigh;
    }

    public Set<RangelBuilding> getEstimatedBurningBuildings() {
        return estimatedBurningBuildings;
    }

    public String getMapName() {
        return getUniqueMapNumber().toString();
    }//获取地图名称

    public Long getUniqueMapNumber() {
        return uniqueMapNumber;
    }//获取唯一的地图编号

    public Building getBuildingInPoint(int x, int y) {//通过xy得到建筑物
        String xy = x + "," + y;
        return buildingXYMap.get(xy);
    }

    public ScenarioInfo getScenarioInfo() {
        return scenarioInfo;
    }

    public void setScenarioInfo(ScenarioInfo scenarioInfo) {
        this.scenarioInfo = scenarioInfo;
    }

    public AgentInfo getAgentInfo() {
        return agentInfo;
    }

    public void setAgentInfo(AgentInfo agentInfo) {
        this.agentInfo = agentInfo;
    }

    public WorldInfo getWorldInfo() {
        return worldInfo;
    }

    public void setWorldInfo(WorldInfo worldInfo) {
        this.worldInfo = worldInfo;
    }

    public Set<EntityID> getBuildingIDs() {
        Set<EntityID> buildingIDs = new HashSet<>();
        Collection<StandardEntity> buildings = getBuildings();
        for (StandardEntity entity : buildings) {
            buildingIDs.add(entity.getID());
        }

        return buildingIDs;
    }

    public Set<EntityID> getBorderBuildings() {
        return borderBuildings;
    }

    public int getMapWidth() {
        return maxX - minX;
    }

    public int getMapHeight() {
        return maxY - minY;
    }

    public int getTime() {
        return agentInfo.getTime();
    }

    public int getMaxExtinguishDistance() {
        return scenarioInfo.getFireExtinguishMaxDistance();

    }

    public int getDistance(EntityID first, EntityID second) {
        return worldInfo.getDistance(first, second);
    }

    public int getDistance(StandardEntity first, StandardEntity second) {
        return worldInfo.getDistance(first, second);
    }


    public Collection<StandardEntity> getFireBrigades() {
        return worldInfo.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE);
    }

    public Collection<StandardEntity> getObjectsInRange(int x, int y, int range) {//获取范围内的对象
        int newRange = (int) (0.64 * range);
        return worldInfo.getObjectsInRange(x, y, newRange);
    }

    public boolean isMapHuge() {
        return isMapHuge;
    }

    public boolean isMapMedium() {
        return isMapMedium;
    }

    public List<StandardEntity> getBuildingsInShape(Shape shape) {//根据形状找建筑物
        List<StandardEntity> result = new ArrayList<StandardEntity>();
        for (StandardEntity next : getBuildings()) {
            Area area = (Area) next;
            if (shape.contains(area.getShape().getBounds2D()))
                result.add(next);
        }
        return result;
    }

    public List<StandardEntity> getEntities(Set<EntityID> entityIDs) {//获取实体
        List<StandardEntity> result = new ArrayList<StandardEntity>();
        for (EntityID next : entityIDs) {
            result.add(getEntity(next));
        }
        return result;
    }

    public List<StandardEntity> getEntities(List<EntityID> entityIDs) {
        List<StandardEntity> result = new ArrayList<StandardEntity>();
        for (EntityID next : entityIDs) {
            result.add(getEntity(next));
        }
        return result;
    }

    public Set<EntityID> getPossibleBurningBuildings() {
        return possibleBurningBuildings;
    }

    public Set<EntityID> getAllCivilians() {
        return allCivilians;
    }//世界模型中定义了所有平民或他们的声音

    public int getVoiceRange() {
        return scenarioInfo.getRawConfig().getIntValue(RangelConstants.VOICE_RANGE_KEY);
    }

    public Set<EntityID> getHeardCivilians() {
        return heardCivilians;
    }

    public void addHeardCivilian(EntityID civID) {
        if (!heardCivilians.contains(civID)) {
            heardCivilians.add(civID);
        }
    }

    public Pair<Integer, Integer> getSelfLocation() {
        return worldInfo.getLocation(agentInfo.getID());
    }

    public boolean isBuildingBurnt(Building building) {//是否是正在燃烧的建筑物
        if (building == null || !building.isFierynessDefined()) {
            return false;
        }
        int fieriness = building.getFieryness();

        return fieriness != 0 && fieriness != 4 && fieriness != 5;
    }

    public int getViewDistance() {
        return scenarioInfo.getPerceptionLosMaxDistance();
    }

    public void setExploreTarget(EntityID exploreTarget) {
        this.exploreTarget = exploreTarget;
    }

    public EntityID getExploreTarget() {
        return exploreTarget;
    }

    public void flagUnreachable(Area area) {//标记不可达
        if (area instanceof Building) {
            RangelBuilding RangelBuilding = getRangelBuilding(area.getID());
            RangelBuilding.setReachable(false);
        } else if (area instanceof Road) {
            RangelRoad RangelRoad = getRangelRoad(area.getID());
            RangelRoad.setReachable(false);
        }
    }
}
